home *** CD-ROM | disk | FTP | other *** search
- // This software is in the public domain.
- // Permission is granted to use this software for any
- // purpose commercial or non-commercial.
- // The implementer/distributer assume no liability for
- // any damages, incidental, consequential or otherwise,
- // arising from the use of this software.
-
- // Implementation of class interval
- //
- // Most operators are trivial and could be inlined.
- //
- // Multiply is more interesting. The complicated testing
- // may be more time consuming than the floating-point
- // operations it attempts to avoid.
- // How could this testing be streamlined?
- //
- // Note that divide blurts out error/warning messages using fprintf :-(
- // Strictly speaking, division is undefined if the divisor interval
- // contains zero. This code is sloppy in allowing it, but it warns.
- //
- // No attempt is made to control rounding so accuracy is dubious.
- //
- // No attempt is made to detect/recover from overflow or underflow.
- // This is a serious deficiency. Is there a 'portable' around it?
-
- #include <CC/stdio.h>
- #include "interval.h"
-
- interval interval::operator+(interval I)
- {
- interval temp(lo_bound, hi_bound);
- return temp += I;
- }
-
- interval interval::operator-(interval I)
- {
- interval temp(lo_bound, hi_bound);
- return temp -= I;
- }
-
- interval interval::operator*(interval I)
- {
- interval temp(lo_bound, hi_bound);
- return temp *= I;
- }
-
- interval interval::operator/(interval I)
- {
- interval temp(lo_bound, hi_bound);
- return temp /= I;
- }
-
- interval &interval::operator+=(interval I)
- {
- lo_bound += I.lo_bound;
- hi_bound += I.hi_bound;
- return *this;
- }
-
- interval &interval::operator-=(interval I)
- {
- lo_bound -= I.lo_bound;
- hi_bound -= I.hi_bound;
- return *this;
- }
-
- // Multiply is a bit complicated.
- // A naive version simply takes the minimum of all combinations
- // as the new lo_bound and the maximum as the new hi_bound.
- // But this involves four double precision floating multiples.
- // A quick examination of the signs of the intervals reveals
- // that there are nine possible cases of which only one
- // requires all four multiplications. The other cases only
- // require two multiplications. We assume that it is faster to
- // compute and dispatch to the right case than to perform
- // the extra multiplies. If not, use the naive scheme.
- //
- // The cases can be described as follows:
- // Each interval is either non-negative (lo bound >= 0),
- // non-positive (hi bound <= 0), or crosses(includes) zero,
- // including some numbers on either side.
- // If we label the intervals, A and B, corresponding to
- // "this" and "I", we get the following matrix:
- //
- // Bcross Bnonneg Bnonpos
- //
- // Across
- //
- // Anonneg
- //
- // Anonpos
-
- interval &interval::operator*=(interval I)
- {
- enum possibility {
- AcrossBcross, AcrossBnn, AcrossBnp,
- AnnBcross, AnnBnn, AnnBnp,
- AnpBcross, AnpBnn, AnpBnp
- } choice;
-
- if (lo_bound >= 0.0) choice = AnnBcross;
- else if (hi_bound <= 0.0) choice = AnpBcross;
- else choice = AcrossBcross;
-
- if (I.lo_bound >= 0.0) choice += 1;
- else if (I.hi_bound <= 0.0) choice += 2;
-
- switch (choice)
- {
- case AcrossBcross: {
- double HL = hi_bound*I.lo_bound,
- HH = hi_bound*I.hi_bound,
- LL = lo_bound*I.lo_bound,
- LH = lo_bound*I.hi_bound;
- lo_bound = HL<LH?HL:LH;
- hi_bound = LL>HH?LL:HH;
- }
- break;
-
- case AcrossBnn:
- lo_bound *= I.hi_bound;
- hi_bound *= I.hi_bound;
- break;
-
- case AcrossBnp: {
- double new_hi_bound = lo_bound * I.lo_bound;
-
- lo_bound = hi_bound*I.lo_bound;
- hi_bound = new_hi_bound;
- }
- break;
-
- case AnnBcross:
- lo_bound = hi_bound*I.lo_bound;
- hi_bound *= I.hi_bound;
- break;
-
- case AnnBnn:
- lo_bound *= I.lo_bound;
- hi_bound *= I.hi_bound;
- break;
-
- case AnnBnp: {
- double new_hi_bound = lo_bound * I.hi_bound;
-
- lo_bound = hi_bound*I.lo_bound;
- hi_bound = new_hi_bound;
- }
- break;
-
- case AnpBcross:
- hi_bound = lo_bound*I.lo_bound;
- lo_bound *= I.hi_bound;
- break;
-
- case AnpBnn:
- lo_bound *= I.hi_bound;
- hi_bound *= I.lo_bound;
- break;
-
- case AnpBnp: {
- double new_hi_bound = lo_bound * I.lo_bound;
-
- lo_bound = hi_bound*I.hi_bound;
- hi_bound = new_hi_bound;
- }
- break;
-
- default:
- fprintf(stderr,
- "Bad interval (low bound > hi bound) [%f, %f] * [%f, %f]\n",
- lo_bound, hi_bound, I.lo_bound, I.hi_bound);
- lo_bound = hi_bound = 0.0;
- break;
- }
-
- return *this;
- }
-
- interval &interval::operator/=(interval I)
- {
- if (I.lo_bound == 0.0 && I.hi_bound == 0)
- fprintf(stderr, "Error: Division by zero attempted - [%f,%f]/[f,%f]\n",
- lo_bound, hi_bound, I.lo_bound, I.hi_bound);
- else {
- if (I.lo_bound < 0 && I.hi_bound > 0)
- fprintf(stderr, "Warning: Division by zero possible - [%f,%f]/[%f,%f]\n",
- lo_bound, hi_bound, I.lo_bound, I.hi_bound);
- interval inv(1.0/I.lo_bound, 1.0/I.hi_bound);
- return inv *= *this;
- }
- }
-